local util = require "util"
local conf = require "conf"
local require = require
local setmetatable = setmetatable
local error = error
local table = table
local ngx = ngx
local os = os
local string = string
local tonumber = tonumber
local pairs = pairs
package.cpath = "/usr/nginx/?.so;;"
local json = require 'cjson'
module(...)
_VERSION = '0.1'

function  create(user, args)
    local db = conf.get_mysql()
    local decodeURI = util.decodeURI
    local sql = "INSERT INTO `schedule` SET"
    
    if args.sid then
        sql = sql .. " sid = '" .. args.sid .. "',"
    end
    
    if args.aid then
        sql = sql .. " aid = " .. args.aid .. ","
    else
        sql = sql .. " aid = " .. user.aid .. ","
    end

    if args.org_id then
        sql = sql .. " org_id = " .. args.org_id .. ","
    else
        sql = sql .. " org_id = " .. user.org_id .. ","
    end

    if args.eid then
        sql = sql .. " eid = " .. args.eid .. ","
    end

    if args.route_id then
        sql = sql .. " route_id = " .. args.route_id .. ","
    end

    if args.arrive_time then
        sql = sql .. " arrive_time = " .. args.arrive_time .. ","
    end

    if args.takeoff_time then
        sql = sql .. " takeoff_time = " .. args.takeoff_time .. ","
    end
    
    if args.start_time then
        sql = sql .. " start_time = " .. args.start_time .. ","
    end
    
    if args.end_time then
        sql = sql .. " end_time = " .. args.end_time .. "," 
    end
    
    if args.disabled then
        sql = sql .. " disabled = " .. args.disabled .. ","
    end
    
    if args.repeat_on then
        sql = sql .. " repeat_on = " .. ngx.quote_sql_str(args.repeat_on) .. ","
    end
    
    if args.comment then
        sql = sql .. " comment = '" .. args.comment .. "',"
    end
    
    sql = sql .. " flight_number = '" .. getId(user.id, args.sid, args.eid, 1) .. "',"


    sql = sql .. " update_time = " .. os.time() .. ","

    sql = sql .. " create_time = " .. os.time() .. ","

    sql = sql .. " uid = " .. user.id .. ","

    ngx.log(ngx.ERR, sql)
    local res = db:query(sql:sub(1, -2))
    return res
end

function createController(user, args)
    local db = conf.get_mysql()

    if args.sid and args.eid then
        if args.sid == args.eid then
            ngx.print(json.encode({
                err = 1,
                msg = '起始站点和结束站点不可一样'
            }))
            ngx.exit(200)
        end
    end

    if args.arrive_time < args.takeoff_time then
        if args.sid == args.eid then
            ngx.print(json.encode({
                err = 1,
                msg = '计划起飞时间需大于计划到达时间'
            }))
            ngx.exit(200)
        end
    end

    local res = create(user, args)
    if not res or res.affected_rows < 1 then
        ngx.print(json.encode({
            err = 1,
            msg = '创建失败'
        }))
        ngx.exit(200)
    else
        local insert_id = res.insert_id
        if insert_id < 1 then
            res = db:query("SELECT LAST_INSERT_ID() AS insert_id")
            if res and res[1] and res[1].insert_id then
                insert_id = res[1].insert_id
            end
        end
        ngx.print(json.encode({
            err = 0,
            id = insert_id,
            msg = '创建成功'
        }))
        ngx.exit(200)
    end 
end

function update(user, args)
    local db = conf.get_mysql()
    local decodeURI = util.decodeURI
    local sql = "UPDATE `schedule` SET "
    
    if args.sid then
        sql = sql .. " sid = " .. args.sid .. ","
    end

    if args.aid then
        sql = sql .. " aid = " .. args.aid .. ","
    end

    if args.org_id then
        sql = sql .. " org_id = " .. args.org_id .. ","
    end

    if args.eid then
        sql = sql .. " eid = " .. args.eid .. ","
    end

    if args.arrive_time then
        sql = sql .. " arrive_time = " .. args.arrive_time .. ","
    end
    if args.takeoff_time then
        sql = sql .. " takeoff_time = " .. args.takeoff_time .. ","
    end
    if args.disabled then
        sql = sql .. " disabled = " .. args.disabled .. ","
    end
    if args.repeat_on then
        sql = sql .. " repeat_on = '" .. args.repeat_on .. "',"
    end
    if args.comment then
        sql = sql .. " comment = '" .. args.comment .. "',"
    end
    if args.route_id then
        sql = sql .. " route_id = " .. args.route_id .. ","
    end

    sql = sql .. " flight_number = '" .. getId(user.id, args.sid, args.eid, 0) .. "',"

    if args.disabled then
        sql = sql .. " disabled = " .. args.disabled .. ","
    end

    if args.start_time then
        sql = sql .. " start_time = " .. args.start_time .. ","
    end
    if args.end_time then
        sql = sql .. " end_time = " .. args.end_time .. ","
    end

    sql = sql .. " update_time = " .. os.time() .. ","

    sql = sql .. " aid = " .. user.aid .. ","

    sql = sql .. " uid = " .. user.id .. ","
    
    sql = sql:sub(1, -2) .. " WHERE id = " .. args.id
    ngx.log(ngx.ERR, sql)
    local res = db:query(sql)
end

function updateController(user, args)
    if not args.id or args.id == ngx.NULL then
        ngx.print(json.encode({
            err = 2,
            msg = '缺少id'
        }))
        ngx.exit(200)
    end
    local res = update(user, args)
    if not res then
        ngx.print(json.encode({
            err = 1,
            msg = '更新失败'
        }))
        ngx.exit(200)
    else 
        ngx.print(json.encode({
            err = 0,
            msg = res
        }))
        ngx.exit(200)
    end
end

function search(user, args)
    local page_no, page_size, id, sname, ename, aid, sid, eid, start_time, end_time, airport = tonumber(args.page_no), tonumber(args.page_size), args.id, args.sname, args.ename, args.aid, args.sid, args.eid, args.start_time, args.end_time, args.airport
    local db = conf.get_mysql()
    local sql = "SELECT *,`schedule`.id, (SELECT name from spoint where id = `schedule`.sid) AS sname,(SELECT name from spoint where id = `schedule`.eid) AS ename, `area`.name as area FROM `schedule` left join `area` on `schedule`.aid = `area`.id WHERE 1 = 1";
    if sname then
        sql = sql .. " AND (SELECT name from spoint where id = `schedule`.sid) like '%" .. sname .. "%'"
    end
    if ename then
        sql = sql .. " AND (SELECT name from spoint where id = `schedule`.eid) like '%" .. ename .. "%'"
    end
    
    if area then
        sql = sql .. " AND area like '%" .. area .. "%'"
    end

    if name then
        sql = sql .. " AND `schedule`.name like '%" .. name .. "%'"
    end

    if id and tonumber(id) then
        sql = sql .. " AND `schedule`.id = " .. tonumber(id)
    end

    if aid then
        local ids = conf.get_aids(tonumber(aid))
        sql = sql .. " AND `schedule`.aid in (" ..  table.concat(ids, ",") .. ")"
    end

    if args.org_id then
        local ids = conf.get_orgIds(tonumber(args.org_id))
        sql = sql .. " AND `schedule`.org_id in (" ..  table.concat(ids, ",") .. ")"
    end
    
    if sid then
        sql = sql .. " AND `schedule`.sid = " .. sid
    end
    
    if airport then
        sql = sql .. " AND (`schedule`.sid = " .. airport .. " OR `schedule`.eid = " .. airport .. ")"
    end

    if start_time then
        sql = sql .. " AND `schedule`.start_time <= " .. tonumber(start_time)
    end

    if end_time then
        sql = sql .. " AND `schedule`.end_time >= " .. tonumber(end_time)
    end
    if eid then
        sql = sql .. " AND `schedule`.eid = " .. eid
    end

    sql = sql .. " AND `schedule`.aid in (" ..  table.concat(user.aids, ",") .. ")"

    sql = sql .. " AND `schedule`.org_id in (" ..  table.concat(user.orgIds, ",") .. ")"

    sql = sql .. " ORDER BY `schedule`.takeoff_time ASC"
    
    local count = #(db:query(sql) or {})

    if page_no and page_size then
        sql = sql ..  " LIMIT " .. (page_no * page_size) .. "," .. page_size
    end
    ngx.log(ngx.ERR, sql)
    local res = db:query(sql)
    return res, count
end

function searchControler(user, args)
    local res, count = search(user, args)
    if not res then
        ngx.print(json.encode({
            err = 1,
            msg = '未找到相应的订单'
        }))
        ngx.exit(200)
    else
        ngx.print(json.encode({
            err = 0,
            msg = res,
            count = count
        }))
        ngx.exit(200)
    end
end

function delete(user, args)
    local id = args.id
    local db = conf.get_mysql()
    

    local res = db:query("DELETE FROM `schedule` WHERE id = " .. id )
    return res
end

function deleteController(user, args)
    if not args.id then
        ngx.print(json.encode({
            err = 2,
            msg = '缺少id'
        }))
    end
    local res = delete(user, args)
    if not res or res.affected_rows < 1 then
        ngx.print(json.encode({
            err = 1,
            msg = '更新失败'
        }))
        ngx.exit(200)
    else 
        ngx.print(json.encode({
            err = 0,
            msg = res
        }))
        ngx.exit(200)
    end
end
-- status:{
--     1: 取消,
--     2: 延误,
--     3: 完成,
--     4: 计划,
--     5: 起飞
-- }

function oneDayDetailControler(user, args)
    local res, percent, dayCount, dayMeter = oneDayDetail(user, args)
    if not res then
        ngx.print(json.encode({
            err = 1,
            msg = '未找到相应的计划'
        }))
        ngx.exit(200)
    else
        ngx.print(json.encode({
            err = 0,
            msg = res,
            dayCount = dayCount,
            dayMeter = dayMeter,
            percent = percent
        }))
        ngx.exit(200)
    end
end

function weekDetailControler(user, args)
    local res, percent, dayCount, dayMeter = weekDetail(user, args)
    if not res then
        ngx.print(json.encode({
            err = 1,
            msg = '未找到相应的计划'
        }))
        ngx.exit(200)
    else
        ngx.print(json.encode({
            err = 0,
            msg = res,
            dayCount = dayCount,
            dayMeter = dayMeter,
            percent = percent
        }))
        ngx.exit(200)
    end
end

function getActiveControler(user, args)
    local res = getActive(user, args)
    if not res then
        ngx.print(json.encode({
            err = 1,
            msg = '未找到相应的计划'
        }))
        ngx.exit(200)
    else
        ngx.print(json.encode({
            err = 0,
            msg = res
        }))
        ngx.exit(200)
    end
end

local function matchOrderWithSchedules(orders, schedules, userSchedules, args)

    local res = {}
    local count = 0
    local total = 0
    local today = util.zero_clock_of_day(args.now)
    for k,s in pairs(schedules) do
        total = total + 1
        local endDay = util.zero_clock_of_day(args.end_time)
        local dueTime = util.zero_clock_of_day(args.now) + tonumber(s.arrive_time)
            -- ngx.log(ngx.ERR, "endDay is " .. endDay .. ": " .. os.date("%c", endDay))
            -- ngx.log(ngx.ERR, "end_time is " .. args.end_time .. ": " .. os.date("%c", args.end_time))
            -- ngx.log(ngx.ERR, "now is " .. args.now .. ": " .. os.date("%c", args.now))
            -- ngx.log(ngx.ERR, "dueTime is " .. dueTime .. ": " .. os.date("%c", dueTime))
            -- ngx.log(ngx.ERR, "today is " .. today .. ": " .. os.date("%c", today))

        if endDay > today then
            schedules[k].status = 4
        else
            if args.now < dueTime then 
                schedules[k].status = 4
            else
                schedules[k].status = 2
            end
            for k1, o in pairs(orders) do
                if tonumber(s.id) == tonumber(o.schedule_id) then
                    -- if o.t2 > 0 then
                        ngx.log(ngx.ERR, o.id)
                        schedules[k].status = 5
                        if (o.t4 > 0 and o.t4 <= dueTime) or (o.t5 > 0 and o.t5 <= dueTime) then
                            schedules[k].status = 3
                            count = count + 1
                        elseif o.t4 > dueTime or o.t5 > dueTime then
                            schedules[k].status = 2
                            count = count + 1
                        end
                    -- end
                end
            end
            
            if endDay < today then

                if schedules[k].status == 2 or schedules[k].status == 4 then
                    schedules[k].status = 1
                end
            end
        end
        -- ngx.log(ngx.ERR, json.encode(userSchedules))
        for k2, us in pairs(userSchedules) do
            if us.schedule_id == s.id then
                if not schedules[k].cancleInfo then
                    schedules[k].cancleInfo = {}
                end
                if not schedules[k].cancleInfo[us.schedule_date .. ""] then
                    schedules[k].cancleInfo[us.schedule_date .. ""] = {}
                end
                table.insert(schedules[k].cancleInfo[us.schedule_date .. ""], us)
                schedules[k].cancleInfo[us.schedule_date .. ""].ifCancle = not schedules[k].cancleInfo[us.schedule_date .. ""].ifCancle
            end
        end
        if schedules[k].cancleInfo then
            for kc,ci in pairs(schedules[k].cancleInfo) do
                if ci.ifCancle then
                    schedules[k].status = 1
                end
            end
        end
        schedules[k].date = args.start_time
        table.insert(res, schedules[k])
    end

    local len = total == 0 and 1 or total
    local percent = string.format("%0.1f", count/len or 0)
    return res, percent
end

local function getActiveSchedules(schedules, start_time, end_time)
    local schs = {}
    for k,v in pairs(schedules) do
        local days = util.split(v.repeat_on, ",")
        local date = os.date("%w", end_time)
        -- ngx.log(ngx.ERR, date)
        if util.contains(days, date) then
            table.insert(schs, v)
        end
    end
    return schs   
end

function oneDayDetail(user, args)
    local db = conf.get_mysql()
    local order = require "order"
    local now = os.time()
    args.start_time = args.start_time or util.zero_clock_of_day(now)
    args.end_time = args.end_time or util.zero_clock_of_day(now) + 86400 - 1
    args.now = args.now or os.time()
    -- ngx.log(ngx.ERR, json.encode(args))
    local orders = order.calcOneDayOrderStats(user, args) or {}
    ngx.log(ngx.ERR, json.encode(orders))
    local dayCount = #orders
    local dayMeter = util.reduce(orders, function(mem, n)  return tonumber(n.distance) + mem end, 0)

    local schedules = search(user, args)

    schedules = getActiveSchedules(schedules, args.start_time, args.end_time)
    local scheduleIds = {}
    for k,v in pairs(schedules) do
        table.insert(scheduleIds, v.id)
    end
    
    -- ngx.log(ngx.ERR, json.encode(schedules))

    local userSchedules = db:query("SELECT * FROM `user_schedule` WHERE schedule_date >= " .. args.start_time .. " AND schedule_date <= " .. args.end_time)
    local order, percent = matchOrderWithSchedules(orders, schedules, userSchedules, args)
    return order,percent, dayCount, dayMeter
end


function weekDetail(user, args)
    local now = os.time()
    local weekDate = args.now or now
    local sunday = util.zero_clock_of_sunday(args.now)
    ngx.log(ngx.ERR, sunday)
    local orders = {}
    local order,percent,dayCount, dayMeter,todayCount, todayMeter, todayPercent
    for i = 0,6 do
        args.start_time = i * 86400 + sunday
        args.end_time = args.start_time + 86400 - 1
        args.now = now
        order,percent,dayCount, dayMeter = oneDayDetail(user, args)
        if os.date("%x", args.start_time) == os.date("%x", now) then
            todayCount = dayCount
            todayMeter = dayMeter
            todayPercent = percent
        end
        for k,v in pairs(order) do
            orders[i..""] = order
        end
    end
    return orders, todayPercent, todayCount, todayMeter
end

function getActive(user, args)
    local today = args.today or os.time()
    local todayStart = util.zero_clock_of_day(today)
    local todayEnd =todayStart + 86400 - 1
    args.start_time = todayStart
    args.end_time = todayEnd
    local schedules = search(user, args)
    schedules = getActiveSchedules(schedules, start_time, end_time)
    return schedules
end

function getActiveSpoints(user, args)
    local schedules = getActive(user, args)
    local spoints = {}
    for k,v in pairs(schedules) do
        if not spoints[v.sid .. ""] then
            spoints[v.sid .. ""] = {planArrive = 0, planTakeoff = 0}
        else
            spoints[v.sid .. ""].planArrive = spoints[v.sid .. ""].planArrive + 1
        end

        if not spoints[v.eid .. ""] then
            spoints[v.eid .. ""] = {planArrive = 0, planTakeoff = 0}
        else
            spoints[v.sid .. ""].planTakeoff = spoints[v.sid .. ""].planTakeoff + 1
        end
    end
    return spoints
end

function  getId(uid, sid, eid, update)
    local db = conf.get_mysql()
    local orgName = db:query("SELECT `organization`.name FROM `organization` left join `user` on `user`.org_id = `organization`.id WHERE `user`.id = " .. uid)
    orgName = orgName[1].name
    local count = db:query("SELECT count(id) FROM `schedule` where sid = " .. sid) --.. " AND " .. "eid = " .. eid)
    ngx.log(ngx.ERR, json.encode(count))
    count = tonumber(count[1]["count(id)"]) + update
    return orgName .. string.format("%03d", sid) .. util.dec_hex(count)
end

function getTempId(uid, sid, eid)
    local db = conf.get_mysql()
    local orgName = db:query("SELECT `organization`.name FROM `organization` left join `user` on `user`.org_id = `organization`.id WHERE `user`.id = " .. uid)
    orgName = orgName[1].name
    return orgName .. string.format("%03d", sid) .. "X"
end
-- action = 0 恢复
-- action = 1 取消
function cancle(user, args)
    local db = conf.get_mysql()
    -- ngx.log(ngx.ERR, args.schedule_id)

    local res = db:query("SELECT flight_number, uid FROM `schedule` WHERE id = " .. args.schedule_id)
    if not res or #res == 0 then
        return nil
    end
    -- ngx.log(ngx.ERR, json.encode(res))
    local to_uid = tonumber(res[1].uid)
    local flight_number = res[1].flight_number
    local message = require "message"
    if to_uid ~= user.id then
        message.createCancleScheduleMessage(user, {["to_uid"] = to_uid, ["schedule_date"]= args.schedule_date, ["opt"] = args.opt, ["flight_number"]= flight_number})
    end
    local vals = {}
    local schedule_id, schedule_date, opt = args.schedule_id, args.schedule_date, args.opt
    vals[#vals + 1] = " schedule_id = " .. schedule_id
    vals[#vals + 1] = " schedule_date = " .. util.zero_clock_of_day(schedule_date)
    vals[#vals + 1] = " opt = " .. opt
    vals[#vals + 1] = " create_time = " .. os.time()
    vals[#vals + 1] = " user_name = " .. ngx.quote_sql_str(user.name)
    local sql = "INSERT INTO `user_schedule` SET " .. table.concat(vals, ",")
     ngx.log(ngx.ERR, sql)
    local res = db:query(sql)
    return res
end

function cancleController(user, args)
    if not args.schedule_id or  not args.schedule_date or not args.opt then
        ngx.print(json.encode({
            err = 1,
            msg = "缺少参数"
        }))
        ngx.exit(200)
    end

    local res = cancle(user, args)
    if not res then
        ngx.print(json.encode({
            err = 1,
            msg = '权限不足'
        }))
        ngx.exit(200)
    else
        ngx.print(json.encode({
            err = 0,
            msg = "成功"
        }))
        ngx.exit(200)
    end 
end

function default(args)
    if args.action == 'create' then
        local user = conf.parse_token(args, "schedule")
        createController(user, args)
    elseif args.action == 'update' then
        local user = conf.parse_token(args, "schedule")
        updateController(user, args)
    elseif args.action == 'search' then
        local user = conf.parse_token(args, "schedule")
        searchControler(user, args)
    elseif args.action == 'delete' then
        local user = conf.parse_token(args, "schedule")
        deleteController(user, args)
    elseif args.action == 'cancle' then
        local user = conf.parse_token(args, "schedule")
        cancleController(user, args)
    elseif args.action == 'oneDayDetail' then
        local user = conf.parse_token(args, "schedule")
        oneDayDetailControler(user, args)
   elseif args.action == 'getActive' then
        local user = conf.parse_token(args, "schedule")
        getActiveControler(user, args)
    elseif args.action == 'weekDetail' then
        local user = conf.parse_token(args, "schedule")
        weekDetailControler(user, args)
    end
end

local class_mt = {
    __newindex = function (table, key, val)
        error('attempt to write to undeclared variable "' .. key .. '"')
    end
}
setmetatable(_M, class_mt)
